package cn.iocoder.yudao.framework.business.basic.dao.mapper;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.business.basic.dao.query.CoreLambdaQueryWrapper;
import cn.iocoder.yudao.framework.business.basic.dao.query.CoreQueryWrapper;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.github.yulichang.base.MPJBaseMapper;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 在 MyBatis Plus 的 BaseMapper 的基础上拓展，提供更多的能力：
 * 1. {@link com.baomidou.mybatisplus.core.mapper.BaseMapper} 为 MyBatis Plus 的基础接口，提供基础的 CRUD 能力
 * 2. {@link MPJBaseMapper} 为 MyBatis Plus Join 的基础接口，提供连表 Join 能力
 * 3. {@link BaseMapperX} 为 MyBatis Plus Join 的基础接口，提供连表 Join 能力
 * 4. 修复 {@link #selectOne} 限制只返回一条但实际可能返回多条问题
 */
public interface CoreMapper<DO> extends BaseMapperX<DO> {

    @Override
    default DO selectOne(String field, Object value) {
        CoreQueryWrapper<DO> wrapper = new CoreQueryWrapper<>();
        wrapper.eq(field, value);
        wrapper.limitN(1);
        return selectOne(wrapper);
    }

    @Override
    default DO selectOne(SFunction<DO, ?> field, Object value) {
        CoreLambdaQueryWrapper<DO> wrapper = new CoreLambdaQueryWrapper<>();
        wrapper.eq(field, value);
        wrapper.limitN(1);
        return selectOne(wrapper);
    }

    @Override
    default DO selectOne(String field1, Object value1, String field2, Object value2) {
        CoreQueryWrapper<DO> wrapper = new CoreQueryWrapper<>();
        wrapper.eq(field1, value1);
        wrapper.eq(field2, value2);
        wrapper.limitN(1);
        return selectOne(wrapper);
    }

    @Override
    default DO selectOne(SFunction<DO, ?> field1, Object value1, SFunction<DO, ?> field2, Object value2) {
        CoreLambdaQueryWrapper<DO> wrapper = new CoreLambdaQueryWrapper<>();
        wrapper.eq(field1, value1);
        wrapper.eq(field2, value2);
        wrapper.limitN(1);
        return selectOne(wrapper);
    }

    @Override
    default DO selectOne(SFunction<DO, ?> field1, Object value1, SFunction<DO, ?> field2, Object value2,
                         SFunction<DO, ?> field3, Object value3) {
        CoreLambdaQueryWrapper<DO> wrapper = new CoreLambdaQueryWrapper<>();
        wrapper.eq(field1, value1);
        wrapper.eq(field2, value2);
        wrapper.eq(field3, value3);
        wrapper.limitN(1);
        return selectOne(wrapper);
    }

    @Override
    default DO selectOne(Wrapper<DO> queryWrapper) {
        return this.selectOne(queryWrapper, true);
    }

    @Override
    default DO selectOne(Wrapper<DO> wrapper, boolean throwEx) {
        String sqlSegment = wrapper.getSqlSegment();
        if (StrUtil.containsIgnoreCase(sqlSegment, "LIMIT")) {
            return BaseMapperX.super.selectOne(wrapper, throwEx);
        }
        if (wrapper instanceof CoreQueryWrapper<DO> coreQueryWrapper) {
            coreQueryWrapper.limitN(1);
            return BaseMapperX.super.selectOne(coreQueryWrapper, throwEx);
        }
        if (wrapper instanceof QueryWrapperX<DO> queryWrapperX) {
            queryWrapperX.limitN(1);
            return BaseMapperX.super.selectOne(queryWrapperX, throwEx);
        }
        if (wrapper instanceof CoreLambdaQueryWrapper<DO> lambdaQueryWrapper) {
            lambdaQueryWrapper.limitN(1);
            return BaseMapperX.super.selectOne(lambdaQueryWrapper, throwEx);
        }
        if (wrapper instanceof LambdaQueryWrapperX<DO> lambdaQueryWrapperX) {
            lambdaQueryWrapperX.limitN(1);
            return BaseMapperX.super.selectOne(lambdaQueryWrapperX, throwEx);
        }
        throw new IllegalArgumentException("缺少 LIMIT 1 片段");
    }

    /**
     * <pre>
     * 查询指定字段的集合
     * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
     *         LambdaQueryWrapper<ProductSpuDO> wrapper = new LambdaQueryWrapper<>();
     *         wrapper.select(ProductSpuDO::getShopId);
     *         wrapper.in(ProductSpuDO::getPlatformCategoryId, ids);
     *         wrapper.groupBy(ProductSpuDO::getShopId);
     *         return selectObjs(wrapper, ProductSpuDO::getShopId);
     * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
     * </pre>
     * @see com.baomidou.mybatisplus.extension.toolkit.Db#listObjs(AbstractWrapper, SFunction)
     */
    default <R> List<R> selectObjs(Wrapper<DO> wrapper, SFunction<? super DO, R> mapper) {
        List<DO> list = selectList(wrapper);
        if (CollUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        return list.stream().map(mapper).collect(Collectors.toList());
    }

    default PageResult<DO> selectPage(Integer current, Integer size, QueryWrapper<DO> wrapper) {
        return selectPage(new PageParam().setPageNo(current).setPageSize(size), wrapper);
    }

}
